/**
 * RemovableDailyRollingFileAppender.java
 */
package com.mht2017.common.logger;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;

import com.mht2017.common.utils.SizeUtil;
import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;


/**
 * @author yutong.xiao
 */
public class RemovableDailyRollingFileAppender extends DailyRollingFileAppender {

	/** 缺省为7天，可以更改 **/
	private static int logKeepDays = 7;

	private static final Timer TIMER = new Timer(RemoveOldLogsTask.class.getSimpleName() + "_Timer", true);

	public static void setLogKeepDays(int logKeepDays) {
		RemovableDailyRollingFileAppender.logKeepDays = logKeepDays;
	}

	public RemovableDailyRollingFileAppender() {
		super();
		schedule();
	}

	public RemovableDailyRollingFileAppender(Layout layout, String filename, String datePattern) throws IOException {
		super(layout, filename, datePattern);
		schedule();
	}

	private void schedule() {
		TIMER.scheduleAtFixedRate(new RemoveOldLogsTask(), 1000, 24 * 3600 * 1000); // 一天
	}

	private class RemoveOldLogsTask extends TimerTask implements FilenameFilter {

		private final String actionName = "清理旧日志文件任务";
		private String fileNameOnly;

		@Override
		public void run() {
			if (null == fileName) {
				return;
			}

			try {
				LogLog.debug(String.format("%s-保留最近的'%s'个文件(%s)", actionName, logKeepDays, fileName));
				File targetFile = new File(fileName);
				fileNameOnly = targetFile.getName();
				File[] listFiles = targetFile.getParentFile().listFiles(this);
				if (SizeUtil.size(listFiles) > logKeepDays) {
					Map<String, List<File>> map = groupByDay(listFiles);
					int toDeleteSize = SizeUtil.size(map) - logKeepDays;
					if (toDeleteSize > 0) {
						doDelete(pickToDeleteFiles(map, toDeleteSize));
					}
				}
			} catch (Exception e) {
				LogLog.error(String.format("%s-任务出错: '%s'", actionName, e.getMessage()), e);
			}
		}

		private Map<String, List<File>> groupByDay(File[] listFiles) {
			SimpleDateFormat dayFormater = new SimpleDateFormat("yyyy-MM-dd");
			String datePattern = getDatePattern();
			String format = datePattern.indexOf('\'') >= 0 ? String.format("'%s%s", fileNameOnly, datePattern.replaceFirst("^'", "")) : String.format("'%s.'%s", fileNameOnly, datePattern);
			SimpleDateFormat fileNameDateFormater = new SimpleDateFormat(format);
			Map<String, List<File>> map = new HashMap<>();
			for (File oneFile : listFiles) {
				Date date = null;
				try {
					date = fileNameDateFormater.parse(oneFile.getName());
				} catch (Exception e) {
					date = new Date(oneFile.lastModified());
				}
				if (null != date) {
					String day = dayFormater.format(date);
					List<File> list = map.get(day);
					if (null == list) {
						map.put(day, list = new LinkedList<>());
					}
					list.add(oneFile);
				}
			}
			return map;
		}

		private List<File> pickToDeleteFiles(Map<String, List<File>> map, int deleteSize) {
			TreeSet<String> treeSet = new TreeSet<>(map.keySet());
			List<File> toDeleteFiles = new LinkedList<>();
			for (int i = 0; i < deleteSize; i++) {
				toDeleteFiles.addAll(map.get(treeSet.pollFirst()));
			}
			return toDeleteFiles;
		}

		private void doDelete(List<File> toDeleteFiles) {
			for (File file : toDeleteFiles) {
				LogLog.warn(String.format("%s-删除日志文件: '%s', 结果: '%s'", actionName, file.getAbsolutePath(), file.delete()));
			}
		}

		@Override
		public boolean accept(File dir, String name) {
			return null == name ? false : name.startsWith(fileNameOnly);
		}

	}

}
